#include "../inc/ButtonManager.h"

#ifndef NULL
#define NULL ((void *)0)
#endif

#define CONFIG_SINGAL_BUTTON_DISABLE_TICKS 500u  // 组合键松开后单键的屏蔽时间，默认500ms

static ButtonNode *ButtonManagerFindButtonById(uint8_t id);
static ButtonGroupNode *ButtonManagerFindGroupById(uint8_t id);

// 单键处理屏蔽计数
static uint16_t singalButtonDisableTick = 0;

// 按钮链表
static ButtonNode *buttonList = NULL;

// 当前已按下的按键数目
static uint8_t pressedButtonNum = 0;

// 组合键判断链表
static ButtonGroupNode *buttonGroupList = NULL;

/**
 * @brief 添加一个按钮到管理器
 * @param buttonNone 按钮节点
 * @param buttonEventCb 按钮事件回调函数
 */
void ButtonManagerAddButton(ButtonNode *buttonNode, ButtonEventCb buttonEventCb)
{
    uint8_t targetId = 1;
    ButtonNode *p = buttonList;

    if (buttonNode == NULL || buttonEventCb == NULL)
        return;

    buttonNode->enable = ButtonTrue;
    buttonNode->pressed = ButtonFalse;
    buttonNode->event = ButtonEventNone;
    buttonNode->eventCb = buttonEventCb;
    buttonNode->next = NULL;

    if (buttonList == NULL)
    {
        buttonNode->id = 0;
        buttonList = buttonNode;
        return;
    }

    for (; p->next != NULL; p = p->next)
        ++targetId; // 计算ID

    buttonNode->id = targetId;
    p->next = buttonNode; // 插入表尾
}

/**
 * @brief 添加一组组合键到管理器
 * @param buttonGroupNode 组合键节点
 * @param buttonGroupEventCb 组合键触发事件回调函数
 */
void ButtonManagerAddButtonGroup(ButtonGroupNode *buttonGroupNode, uint16_t longPressTrigTime, ButtonGroupEventCb buttonGroupEventCb)
{
    uint8_t i = 0;
    uint8_t targetId = 1;
    ButtonGroupNode *p = buttonGroupList;

    if (buttonGroupNode == NULL || buttonGroupEventCb == NULL)
        return;

    buttonGroupNode->longPressTrigTime = longPressTrigTime;
    buttonGroupNode->pressTick = 0;
    buttonGroupNode->enable = ButtonTrue;
    buttonGroupNode->eventCb = buttonGroupEventCb;
    buttonGroupNode->next = NULL;

    for (; i < 4; i++)
    {
        buttonGroupNode->items[i].active = ButtonGroudActivePressed;
        buttonGroupNode->items[i].button = NULL;
    }

    if (buttonGroupList == NULL)
    {
        buttonGroupNode->id = 0;
        buttonGroupList = buttonGroupNode;
        return;
    }

    for (; p->next != NULL; p = p->next)
        ++targetId; // 计算ID

    buttonGroupNode->id = targetId;
    p->next = buttonGroupNode; // 插入表尾
}

/**
 * @brief 设置按键组元素
 */
void ButtonManagerGroupSetItem(ButtonGroupNode *buttonGroupNode, uint8_t index, uint8_t id, uint8_t active)
{
    ButtonNode *node;

    if (index > 3)
        return;

    node = ButtonManagerFindButtonById(id);
    if (node != NULL)
    {
        buttonGroupNode->items[index].active = active;
        buttonGroupNode->items[index].button = node;
    }
}

/**
 * @brief 禁用单键
*/
void ButtonManagerDisableButton(uint8_t buttonId)
{
    ButtonNode *p = ButtonManagerFindButtonById(buttonId);
    
    if(p != NULL)
        p->enable = ButtonFalse;
}

/**
 * @brief 启用单键
*/
void ButtonManagerEnableButton(uint8_t buttonId)
{
    ButtonNode *p = ButtonManagerFindButtonById(buttonId);
    
    if(p != NULL)
        p->enable = ButtonTrue;
}

/**
 * @brief 禁用组合键
*/
void ButtonManagerDisableGroup(uint8_t groupId)
{
    ButtonGroupNode *p = ButtonManagerFindGroupById(groupId);
    
    if(p != NULL)
        p->enable = ButtonFalse;
}

/**
 * @brief 启用组合键
*/
void ButtonManagerEnableGroup(uint8_t groupId)
{
    ButtonGroupNode *p = ButtonManagerFindGroupById(groupId);
    
    if(p != NULL)
        p->enable = ButtonTrue;
}

/**
 * @brief 按钮管理器处理
 * @note 请以"ButtonTick"宏指示的时基周期调用
 */
void ButtonManagerHandler(void)
{
    ButtonNode *p = buttonList;
    ButtonGroupNode *pGroup = buttonGroupList;
    uint8_t groupEvent = ButtonTrue;
    uint8_t i = 0;

    for (; p != NULL; p = p->next) // 轮询处理。保存事件
    {
        p->event = ButtonHandler(&p->button);

        switch (p->event)
        {
        case ButtonEventPressTrig:
            p->pressed = ButtonTrue; // 标记按键已按下
            ++pressedButtonNum;
            break;
        case ButtonEventReleaseTrig:
            p->pressed = ButtonFalse; // 标记按键已松开
            --pressedButtonNum;
            break;
        default:;
        }
    }

    // 有两个以上按键被按下且组合键列表不为空
    if (pressedButtonNum > 1) // 进行组合键判断
    {
        singalButtonDisableTick = CONFIG_SINGAL_BUTTON_DISABLE_TICKS / ButtonTick;  // 屏蔽单键时间计数

        for (; pGroup != NULL; pGroup = pGroup->next)
        {
            if(pGroup->enable != ButtonTrue)    // 组合键被禁用
                continue;

            groupEvent = ButtonTrue;

            for (i = 0; i < 4; i++)
            {
                if (pGroup->items[i].button == NULL)    // 按钮对象为空
                    break;

                if (pGroup->items[i].active == ButtonGroudActivePressed) // 按下状态有效
                    groupEvent = groupEvent && pGroup->items[i].button->pressed;
                else
                    groupEvent = groupEvent && !pGroup->items[i].button->pressed;
            }

            if (i != 0 && groupEvent) // 组合键有效
            {
                if (++pGroup->pressTick == pGroup->longPressTrigTime / ButtonTick)
                    pGroup->eventCb(); // 组合键回调处理(长按触发)
                
                break; // 本轮任意组合键有效后不需要再判断后面的组合键
            }
        }
    }
    else // 单按键事件执行
    {
        if (singalButtonDisableTick > 0)
        {
            if (singalButtonDisableTick == CONFIG_SINGAL_BUTTON_DISABLE_TICKS / ButtonTick)
            {
                for (pGroup = buttonGroupList; pGroup != NULL; pGroup = pGroup->next)   // 重置组合键计数
                    pGroup->pressTick = 0; // 计数重置
            }

            --singalButtonDisableTick;
            return;     // 组合键松开完毕后屏蔽单键一段时间
        }

        // 单按键事件处理
        for (p = buttonList; p != NULL; p = p->next)
        {
            if(p->enable != ButtonTrue)    // 按键键被禁用
                continue;

            if (p->event != ButtonEventNone)
            {
                p->eventCb(p->event); // 事件回调处理
                break;
            }
        }
    }
}

/**
 * @brief 通过ID查找ButtonNode对象
 */
static ButtonNode *ButtonManagerFindButtonById(uint8_t id)
{
    ButtonNode *p = buttonList;
    for (; p != NULL; p = p->next)
    {
        if (id == p->id)
            return p;
    }

    return NULL;
}

/**
 * @brief 通过ID查找ButtonGroup对象
 */
static ButtonGroupNode *ButtonManagerFindGroupById(uint8_t id)
{
    ButtonGroupNode *p = buttonGroupList;
    for (; p != NULL; p = p->next)
    {
        if (id == p->id)
            return p;
    }

    return NULL;
}